﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Windows.Threading;

namespace Game3D
{
    /// <summary>
    /// Interaktionslogik für MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private double angle_flat = Math.PI * 3 / 2;
        private double angle_up = 0;
        private double distance = 15;

        Viewbox viewbox;
        Viewport3D viewport3D;
        PerspectiveCamera camera;
        private DispatcherTimer inputs;
        private List<GameMesh> meshes;
        private GameControl gameControl;

        public MainWindow()
        {
            InitializeComponent();

            #region Input-Timer
            {        
                inputs = new DispatcherTimer();
                inputs.Interval = TimeSpan.FromMilliseconds(80);
                inputs.Tick += inputs_Tick;
            }
            #endregion

            // Viewport Width and Height
            Width = GameConstants.ViewportWidth;
            Height = GameConstants.ViewportHeight;

            // Create new Viewbox and add to FormGrid
            viewbox = new Viewbox();
            ContentGrid.Children.Add(viewbox);

            // Create new 3D Viewport
            viewport3D = new Viewport3D();

            // Append 3D Viewport to Viewbox 
            viewbox.Child = viewport3D;

            // Set Width and Height of Viewbox to Width and Height given by GameConstants
            viewport3D.Height = GameConstants.ViewportHeight;
            viewport3D.Width = GameConstants.ViewportWidth;

            #region Camera Setup
            { 
                // Create new PerspectiveCamera
                camera = new PerspectiveCamera();

                // Set position of camera
                camera.Position = new Point3D(4, 5, distance);

                // Set view angle and direction 
                camera.LookDirection = new Vector3D(-2, 0, -distance);

                // Set direction where top of camera should be
                camera.UpDirection = new Vector3D(0, 1, 0);

                // Set field of view of camera
                camera.FieldOfView = 50;

                viewport3D.Camera = camera;
            }
            #endregion

            CreateBasicLighting();
            //CreateBasicMesh();

            // Create new GameMesh-List
            meshes = new List<GameMesh>();

            // Create a new instance of GameControl
            gameControl = new GameControl(meshes);
            gameControl.Viewport3D = viewport3D;
            //gameControl.Test();

            // Generate a Gamefield -> Width: 8; Height: 10
            gameControl.GenerateGamefield(8, 10);

            GameLogic.LogicController logicCtrl = new GameLogic.LogicController(8, 10);
            Point coord = logicCtrl.CreateMovingBlock();

            GameLogic.LogicBlock[,] gameField = logicCtrl.GameField;
            GameLogic.LogicBlock logicBlock = gameField[(int)coord.X, (int)coord.Y];

            GameMesh theMesh = new GameMesh(logicBlock.Type, 360);

            theMesh.Position = new Point((int)coord.X, (int)coord.Y);


            viewport3D.Children.Add(theMesh);


            // Start Inputs-Timer to register the keyboard commands
            inputs.Start();

            //// Create a new GameMesh
            //GameMesh myFirstMesh = new GameMesh(Shape.T, 180);

            //// Add GameMesh to Viewport3D
            //viewport3D.Children.Add(myFirstMesh);

            //// Move created GameMesh to a new position
            //myFirstMesh.Position = new Point(2, 3);
            
            //// Add two new GameMesh-Objects
            //meshes.Add(new GameMesh(Shape.J, 90));
            //meshes.Add(new GameMesh(Shape.S, 360));

            //// Move them to other positions
            //meshes[meshes.Count - 2].Position = new Point(4, 2);
            //meshes[meshes.Count - 1].Position = new Point(3, 6);

            //// Add them to Viewport3D
            //viewport3D.Children.Add(meshes[meshes.Count - 2]);
            //viewport3D.Children.Add(meshes[meshes.Count - 1]);

            KeyDown += (s, a) =>
            {
                #region flach
                if (Keyboard.IsKeyDown(Key.Left))
                {
                    angle_flat += Math.PI / 36;

                    camera.Position = new Point3D(
                        distance * Math.Cos(angle_flat),
                        camera.Position.Y,
                        -distance * Math.Sin(angle_flat));

                    camera.LookDirection = new Vector3D(
                        -camera.Position.X,
                        -camera.Position.Y,
                        -camera.Position.Z);
                }

                if (Keyboard.IsKeyDown(Key.Right))
                {
                    angle_flat -= Math.PI / 36;

                    camera.Position = new Point3D(
                        distance * Math.Cos(angle_flat),
                        camera.Position.Y,
                        -distance * Math.Sin(angle_flat));

                    camera.LookDirection = new Vector3D(
                        -camera.Position.X,
                        -camera.Position.Y,
                        -camera.Position.Z);
                }
                #endregion

                #region hoch
                if (Keyboard.IsKeyDown(Key.Up))
                {
                    angle_up += Math.PI / 36;

                    camera.Position = new Point3D(
                        camera.Position.X,
                        distance * Math.Sin(angle_up),
                        distance * Math.Cos(angle_up));

                    camera.LookDirection = new Vector3D(
                        -camera.Position.X,
                        -camera.Position.Y,
                        -camera.Position.Z);
                }

                if (Keyboard.IsKeyDown(Key.Down))
                {
                    angle_up -= Math.PI / 36;

                    camera.Position = new Point3D(
                        camera.Position.X,
                        distance * Math.Sin(angle_up),
                        distance * Math.Cos(angle_up));

                    camera.LookDirection = new Vector3D(
                        -camera.Position.X,
                        -camera.Position.Y,
                        -camera.Position.Z);
                }
                #endregion

                #region depth
                if (Keyboard.IsKeyDown(Key.W))
                {
                    distance -= 0.5;

                    double length = Math.Sqrt(
                        Math.Pow(camera.Position.X, 2)
                        + Math.Pow(camera.Position.Y, 2)
                        + Math.Pow(camera.Position.Z, 2)
                        );

                    camera.Position = new Point3D(
                        camera.Position.X / length * distance,
                        camera.Position.Y / length * distance,
                        camera.Position.Z / length * distance);

                    camera.LookDirection = new Vector3D(
                        -camera.Position.X,
                        -camera.Position.Y,
                        -camera.Position.Z);
                }

                if (Keyboard.IsKeyDown(Key.S))
                {
                    distance += 0.5;

                    double length = Math.Sqrt(
                        Math.Pow(camera.Position.X, 2)
                        + Math.Pow(camera.Position.Y, 2)
                        + Math.Pow(camera.Position.Z, 2)
                        );

                    camera.Position = new Point3D(
                        camera.Position.X / length * distance,
                        camera.Position.Y / length * distance,
                        camera.Position.Z / length * distance);

                    camera.LookDirection = new Vector3D(
                        -camera.Position.X,
                        -camera.Position.Y,
                        -camera.Position.Z);
                }
                #endregion

            };
        }

        

        private void CreateBasicLighting()
        {
            ModelVisual3D lightModelVisual3D = new ModelVisual3D();
            viewport3D.Children.Add(lightModelVisual3D);

            Model3DGroup lightSources = new Model3DGroup();
            lightModelVisual3D.Content = lightSources;

            lightSources.Children.Add(new DirectionalLight(Colors.White, new Vector3D(1, -0.5, -0.5)));
            lightSources.Children.Add(new AmbientLight(Colors.LightGray));
        }

        private void CreateBasicMesh()
        {
            ModelVisual3D basicMeshModel = new ModelVisual3D();
            GeometryModel3D basicGeometryModel = new GeometryModel3D();
            MeshGeometry3D basicMeshGeometry = new MeshGeometry3D();
            viewport3D.Children.Add(basicMeshModel);
            basicMeshModel.Content = basicGeometryModel;
            basicGeometryModel.Geometry = basicMeshGeometry;

            basicGeometryModel.Material = new DiffuseMaterial(GameShapeColors.T);
            //basicGeometryModel.Material = new DiffuseMaterial(
            //    new ImageBrush(
            //            new BitmapImage(new Uri("../../assets/img/BeaverMeadow.jpg", UriKind.Relative))
            //        )
            //    );
            basicGeometryModel.BackMaterial = new DiffuseMaterial(Brushes.Blue);

            basicMeshGeometry.Positions = GameMeshGrid.MeshGrid;
            basicMeshGeometry.Normals = GameMeshNormals.MeshNormals;

            #region additional_stuff
            {
                Point3DCollection modelPositions = new Point3DCollection();

                modelPositions.Add(new Point3D(0, 0, 0));
                modelPositions.Add(new Point3D(1, 0, 0));
                modelPositions.Add(new Point3D(1, 1, 0));
                modelPositions.Add(new Point3D(0, 1, 0));

                modelPositions.Add(new Point3D(0, 0, -1));
                modelPositions.Add(new Point3D(1, 0, -1));
                modelPositions.Add(new Point3D(1, 1, -1));
                modelPositions.Add(new Point3D(0, 1, -1));


                //basicMeshGeometry.Positions = modelPositions;
            

                Int32Collection modelTriangleIndices = new Int32Collection();

                // Front
                modelTriangleIndices.Add(0);
                modelTriangleIndices.Add(1);
                modelTriangleIndices.Add(2);

                modelTriangleIndices.Add(0);
                modelTriangleIndices.Add(2);
                modelTriangleIndices.Add(3);

                // Top
                modelTriangleIndices.Add(3);
                modelTriangleIndices.Add(2);
                modelTriangleIndices.Add(6);

                modelTriangleIndices.Add(3);
                modelTriangleIndices.Add(6);
                modelTriangleIndices.Add(7);

                // Back
                modelTriangleIndices.Add(7);
                modelTriangleIndices.Add(6);
                modelTriangleIndices.Add(5);

                modelTriangleIndices.Add(7);
                modelTriangleIndices.Add(5);
                modelTriangleIndices.Add(4);

                // Bottom
                modelTriangleIndices.Add(1);
                modelTriangleIndices.Add(0);
                modelTriangleIndices.Add(4);

                modelTriangleIndices.Add(1);
                modelTriangleIndices.Add(4);
                modelTriangleIndices.Add(5);

                // Right
                modelTriangleIndices.Add(1);
                modelTriangleIndices.Add(5);
                modelTriangleIndices.Add(6);

                modelTriangleIndices.Add(1);
                modelTriangleIndices.Add(6);
                modelTriangleIndices.Add(2);

                // Left
                modelTriangleIndices.Add(3);
                modelTriangleIndices.Add(7);
                modelTriangleIndices.Add(4);

                modelTriangleIndices.Add(4);
                modelTriangleIndices.Add(0);
                modelTriangleIndices.Add(3);

            }
            #endregion 

            //basicMeshGeometry.TriangleIndices = modelTriangleIndices;
            basicMeshGeometry.TriangleIndices = GameShapes.T;

            RotateTransform3D meshRotation = new RotateTransform3D();
            meshRotation.CenterX = 0.5;
            meshRotation.CenterY = 0.5;
            meshRotation.CenterZ = -0.5;

            AxisAngleRotation3D meshAxisAngleRotation = new AxisAngleRotation3D(new Vector3D(1, 1, 1), 0);
            meshRotation.Rotation = meshAxisAngleRotation;

            Transform3DGroup meshTransform3DGroup = new Transform3DGroup();

            meshTransform3DGroup.Children.Add(meshRotation);

            basicMeshModel.Transform = meshTransform3DGroup;

            DispatcherTimer rotationAnimation = new DispatcherTimer();

            rotationAnimation.Interval = TimeSpan.FromMilliseconds(23);

            rotationAnimation.Tick += (s, a) =>
                {
                    meshAxisAngleRotation.Angle++;
                };

            //rotationAnimation.Start();
        }



        void inputs_Tick(object sender, EventArgs e)
        {
            if (Keyboard.IsKeyDown(Key.J)) 
            {
                gameControl.Move(GameMoveDirections.Left);
            }

            if (Keyboard.IsKeyDown(Key.K))
            {
                gameControl.Move(GameMoveDirections.Down);
            }

            if (Keyboard.IsKeyDown(Key.L))
            {
                gameControl.Move(GameMoveDirections.Right);
            }

            if (Keyboard.IsKeyDown(Key.Space))
            {
                gameControl.Rotate();
            }
        }
    }
}
